﻿using System;
using System.Collections.Generic;
using FluentAssertions;
using System.Linq;
using RandomKatas.Kata05;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;

namespace RandomKataTests
{
    [TestClass]
    public class BloomFilterTest
    {
        [TestMethod]
        public void SmallDictionary()
        {
            var words = new[] { "foo", "bar", "baz" }.ToList();
            var filter = BloomFilter<string>.FromMd5(1000, 5);
            words.ForEach(x => filter.AddItem(x));

            words.ForEach(x => filter.IsInSet(x).Should().BeTrue("because {0} is one of the words", x));

            new[] { "zap", "pop", "zip" }.ToList()
                .ForEach(x => filter.IsInSet(x).Should().BeFalse("because {0} is not one of the words", x));
        }

        [TestMethod]
        public void LargeDictionary()
        {
            var words = new HashSet<string>(
                Properties.Resources.WordList.Split((char[])null, StringSplitOptions.RemoveEmptyEntries));
            foreach (var filterMult in new[] { 2, 4, 8, 16 })
            {
                foreach (var numHashes in new[] { 2, 5, 10, 20 })
                {
                    var filter = BloomFilter<string>.FromMd5(words.Count * filterMult, numHashes);
                    foreach (var word in words)
                        filter.AddItem(word);

                    foreach (var word in words)
                        filter.IsInSet(word).Should().BeTrue("because {0} is in wordlist", word);

                    var falsePositives = 0;
                    var totalTries = 0;
                    for (int i = 0; i < 10000; ++i)
                    {
                        var word = Utils.RandomWord(20);
                        while (words.Contains(word))
                            word = Utils.RandomWord(20);

                        if (filter.IsInSet(word))
                            falsePositives++;
                        totalTries++;
                    }

                    Trace.TraceInformation("{0} bits ({1} * words), {2} hashes.  False positive rate: {3}", 
                        filterMult * words.Count, filterMult, numHashes,
                        (falsePositives / ((double)totalTries)));
                }
            }
        }
    }
}
